import traceback
from flask import Blueprint, request, abort
from flask_restful import reqparse, inputs, Resource, Api, fields, marshal_with
from ....models.database import db, auto_commit
from ....decorator.consolejwt import console_token
from ...res import output_json
from ....libs.unit import formatDate,abort_msg
from ....models.console.menu import Menu
from ....libs.tree import UpdateTable


# 蓝图并放入 restful
menu = Blueprint('menu', __name__, url_prefix='/c-api/menu')
api = Api(menu)

# 统一封装 API 返回值
@api.representation('application/json')
def out_json(data, code, headers=None):
    return output_json(data, code, headers=None)

# 转成树形菜单
def toTree(data,pid):
    tree = []
    for i in data:
        if i.parentid == pid:
            # print("### parentid ###",i.parentid)
            tree.append({'menu_id':i.id,'title':i.name,'expand':True,'children':toTree(data,i.id)})
    return tree

class MenuTree(Resource):
    @console_token
    def get(self):
        with auto_commit():
            c = Menu.query.order_by(Menu.sort.asc()).all()
            c = toTree(c, 0)
        return {'resource':c}

# 下拉菜单
class MenuSelect(Resource):
    @console_token
    def get(self):
        with auto_commit():
            c = Menu.query.order_by(Menu.sort.asc())
            res = []
            f_menus = c.filter(Menu.parentid == 0).all()
            # 只查三级选项出来
            for f in f_menus:
                # 一级
                res.append({'label':f.name,'value':f.id})
                # 二级
                s_menus = c.filter(Menu.parentid == f.id).all()
                for s in s_menus:
                    res.append({'label':'|- ' + s.name,'value':s.id})
                    # 三级
                    t_menus = c.filter(Menu.parentid == s.id).all()
                    for t in t_menus:
                        res.append({'label':'||- ' + t.name,'value':t.id})
        return {'resource': res}


# 左侧导航菜单
class MenuLeft(Resource):
    @console_token
    def get(self):
        with auto_commit():
            c = Menu.query.order_by(Menu.sort.asc(),Menu.id.asc()).all()
            # 要用 list，dict 会默认按 key 重置顺序，坑
            allmenus = []
            tmpmenu = []
            for item in c:
                tmpdict = {'id': item.id, 'name': item.name, 'parentid': item.parentid, 'url': item.url, 'label': item.label, 'sort': item.sort}
                tmpmenu.append(tmpdict)
                # 所有一级的
                if item.parentid == 0:
                    allmenus.append(tmpdict)
            # 循环一级下的所有二级出来
            for item in allmenus:
                tmpdict = []
                for t in tmpmenu:
                    if t.get('parentid') == item.get('id'):
                        tmpdict.append(t)
                item['submenu'] = tmpdict
            # 循环第三层
            for item in allmenus:
                submenu = item.get('submenu')
                for sitem in submenu:
                    there = []
                    for t in tmpmenu:
                        if t.get('parentid') == sitem.get('id'):
                            there.append(t)
                    sitem['there'] = there
        return {'resource': allmenus}


# 封装返回的数据格式
resource_fields = {
    'id': fields.Integer,
    'parentid': fields.Integer,
    'name': fields.String,
    'url': fields.String,
    'label': fields.String,
    'icon': fields.String,
    'display': fields.Integer,
    'sort': fields.Integer
}


class DetailMenu(Resource):
    @console_token
    @marshal_with(resource_fields, envelope='resource')
    def get(self):
        # 请求验证
        parser = reqparse.RequestParser()
        parser.add_argument('menu_id', type=int,
                            help='菜单 ID 必须填写', location=['form', 'args'], required=True, action='store')
        args = parser.parse_args()
        with auto_commit():
            c = Menu.query.filter(Menu.id == args.get('menu_id')).first()
        return c


class CreateMenu(Resource):
    @console_token
    def post(self):
        # 请求验证
        parser = reqparse.RequestParser()
        parser.add_argument('parentid', type=inputs.natural,
                            help='父 ID 必须填写', location=['form', 'args'], required=True, action='store')
        parser.add_argument('name', type=str,
                            help='菜单名称必须填写', location=['form', 'args'], required=True, action='store')
        parser.add_argument('url', type=str,
                            help='链接地址必须填写', location=['form', 'args'], required=True, action='store')
        parser.add_argument('label', type=str,
                            help='权限标识必须填写', location=['form', 'args'], required=True, action='store')
        parser.add_argument('display', type=inputs.positive,
                            help='权限标识必须填写', location=['form', 'args'], required=False, action='store', default=1)
        parser.add_argument('sort', type=inputs.natural,
                            help='权限标识必须填写', location=['form', 'args'], required=False, action='store', default=0)
        args = parser.parse_args()
        with auto_commit():
            c = Menu()
            c.name = args.get('name')
            c.parentid = args.get('parentid')
            c.url = args.get('url')
            c.label = args.get('label')
            c.icon = args.get('icon')
            c.display = args.get('display')
            c.sort = args.get('sort')
            db.session.add(c)
            # 更新表
            t = UpdateTable()
            t.update(Menu)
        return {'resource': ''}


class EditMenu(Resource):
    @console_token
    # @marshal_with(resource_fields, envelope='resource')
    def put(self):
        # 请求验证
        parser = reqparse.RequestParser()
        parser.add_argument('menu_id', type=inputs.positive,
                            help='菜单 ID 必须填写', location=['form', 'args'], required=True, action='store')
        parser.add_argument('parentid', type=inputs.natural,
                            help='父 ID 必须填写', location=['form', 'args'], required=True, action='store')
        parser.add_argument('name', type=str,
                            help='菜单名称必须填写', location=['form', 'args'], required=True, action='store')
        parser.add_argument('url', type=str,
                            help='链接地址必须填写', location=['form', 'args'], required= True, action='store')
        parser.add_argument('label', type=str,
                            help='权限标识必须填写', location=['form', 'args'], required=True, action='store')
        parser.add_argument('display', type=inputs.positive,
                            help='权限标识必须填写', location=['form', 'args'], required=False, action='store',default=1)
        parser.add_argument('sort', type=inputs.natural,
                            help='权限标识必须填写', location=['form', 'args'], required=False, action='store',default=0)
        args = parser.parse_args()
        with auto_commit():
            c = Menu.query.filter(Menu.id == args.get('menu_id')).first()
            c.name = args.get('name')
            c.parentid = args.get('parentid')
            c.url = args.get('url')
            c.label = args.get('label')
            c.icon = args.get('icon')
            c.display = args.get('display')
            c.sort = args.get('sort')
            # 更新表
            t = UpdateTable()
            t.update(Menu)
        return {'resource': ''}


class DeleteMenu(Resource):
    @console_token
    # @marshal_with(resource_fields, envelope='resource')
    def delete(self):
        # 请求验证
        parser = reqparse.RequestParser()
        parser.add_argument('menu_id', type=inputs.positive,
                            help='菜单 ID 必须填写', location=['form', 'args'], required=True, action='store')
        args = parser.parse_args()
        with auto_commit():
            c = Menu.query.filter(Menu.id == args.get('menu_id')).first()
            allids = c.arrchildid.split(',')
            Menu.query.filter(Menu.id.in_(allids)).delete(synchronize_session=False)
            # 更新表
            t = UpdateTable()
            t.update(Menu)
        return {'resource': ''}
        
api.add_resource(MenuTree, '/tree')
api.add_resource(MenuLeft, '/left')
api.add_resource(MenuSelect, '/select')
api.add_resource(DetailMenu, '/detail')
api.add_resource(CreateMenu, '/create')
api.add_resource(EditMenu, '/edit')
api.add_resource(DeleteMenu, '/delete')
